#!/usr/bin/python3
import subprocess
import threading
import time
import datetime
import os
import logging
import glob  # <- 新增这行
import configparser
import shutil

# 读取配置文件
config = configparser.ConfigParser()
config.read('config.ini')

# 获取RTSP摄像头列表
rtsp_list = dict(config['rtsp'])

# 获取脚本所在目录
script_dir = os.path.dirname(os.path.abspath(__file__))

# 处理record_dir和archive_dir路径
record_dir = config['Storage']['record_dir']
if not os.path.isabs(record_dir):
    record_dir = os.path.join(script_dir, record_dir)

archive_dir = config['Storage']['archive_dir']
if not os.path.isabs(archive_dir):
    archive_dir = os.path.join(script_dir, archive_dir)

class CameraThread(threading.Thread):
    def __init__(self, name, rtsp_url):
        super().__init__()
        self.name = name
        self.rtsp_url = rtsp_url
        self.process = None
        self.retry_count = 0
        self.last_failure_time = None
        self.stop_event = threading.Event()
        # self.current_day = time.strftime("%Y-%m-%d")
        self.segment_duration = config['Camera']['segment_duration']
        # 创建日志文件路径
        self.log_path = os.path.join(script_dir, "logs", f"{self.name}.log")
        os.makedirs(os.path.dirname(self.log_path), exist_ok=True)

    def run(self):
        """摄像头录制线程的主逻辑"""
        while not self.stop_event.is_set():
            output_path = os.path.join(record_dir, self.name,)

            cmd = [
                "ffmpeg",                                # 使用ffmpeg命令
                "-i", self.rtsp_url,                     # 输入源
                "-c", "copy",                            # 使用copy编码器
                "-f", "segment",                         # 使用segment格式
                "-rtsp_transport", "tcp",                # 使用tcp传输协议
                "-timeout", "3000000",                   # 设置超时时间
                "-strftime", "1",                        # 使用时间戳作为文件名
                "-reset_timestamps", "1",                # 重置时间戳
                "-segment_time", self.segment_duration,  # 设置分片时间
                "%Y-%m-%d_%H-%M-%S.mp4"                  # 输出文件名
            ]
            os.makedirs(output_path, exist_ok=True)   
            try:
                logging.info(f"Starting {self.name} recording... ")
                # 将日志输出到指定文件
                with open(self.log_path, "a") as log_file:
                    self.process = subprocess.Popen(
                        cmd, stderr=log_file, stdout=log_file, cwd=output_path, universal_newlines=True)

                # 监控进程状态
                while not self.stop_event.is_set():
                    return_code = self.process.poll()
                    if return_code is not None:
                        break
                    time.sleep(1)

                if return_code == 0:
                    logging.info(f"{self.name} ffmpeg正常退出")
                else:
                    logging.error(f"{self.name} ffmpeg异常退出，代码: {return_code}, 执行命令: {str(cmd)}" )

            except Exception as e:
                logging.error(f"{self.name} 启动失败: {str(e)}")

            # 处理重连逻辑
            now = time.time()
            if self.last_failure_time and (now - self.last_failure_time) <= 10:
                self.retry_count += 1
            else:
                self.retry_count = 1

            self.last_failure_time = now

            if self.retry_count >= 3:
                logging.warning(f"{self.name} 10秒内失败3次，等待60秒后重试")
                self.stop_event.wait(60)
                self.retry_count = 0
                self.last_failure_time = None
            else:
                self.stop_event.wait(1)

    def stop(self):
        """停止录制线程"""
        self.stop_event.set()
        if self.process and self.process.poll() is None:
            self.process.terminate()
            try:
                self.process.wait(timeout=5)
            except subprocess.TimeoutExpired:
                self.process.kill()

def organize_files():
    """文件整理函数，根据配置参数执行归档"""
    while True:
        try:
            # 获取配置参数
            archive_interval = int(config['Storage']['archive_interval'])
            archive_older_than = int(config['Storage']['archive_older_than'])

            # 计算归档时间点
            current_time = datetime.datetime.now()
            archive_time = current_time - datetime.timedelta(seconds=archive_older_than)

            # 查找需要归档的文件
            for name in rtsp_list.keys():
                file_pattern = f"*.mp4"
                file_paths = glob.glob(os.path.join(record_dir, name, file_pattern))
                for file_path in file_paths:
                    file_name = os.path.basename(file_path)
                    # file_time_str = file_name.split('_')[0] + '_' + file_name.split('_')[1]
                    try:
                        file_time = datetime.datetime.strptime(file_name, "%Y-%m-%d_%H-%M-%S.mp4")
                    except ValueError:
                        continue

                    # 判断文件时间是否早于安全归档时间
                    if file_time < archive_time:
                        # 创建归档目录
                        year = file_time.year
                        month = file_time.month
                        day = file_time.day
                        archive_path = os.path.join(archive_dir, name, str(year), f"{month:02}", f"{day:02}")
                        os.makedirs(archive_path, exist_ok=True)

                        # 归档文件
                        logging.info(f"归档文件: {file_path} -> {archive_path}")
                        # 删除目标文件（如果存在）
                        dest_file = os.path.join(archive_path, file_name)
                        if os.path.exists(dest_file):
                            os.remove(dest_file)
                        shutil.move(file_path, archive_path)

            time.sleep(archive_interval)  # 根据配置间隔时间执行归档
        except Exception as e:
            logging.error(f"文件整理出错: {str(e)}")
            time.sleep(3600)

if __name__ == "__main__":
    logging.basicConfig(
        level=logging.INFO,
        format='%(asctime)s - %(levelname)s - %(message)s'
    )

    # 创建记录和归档目录
    os.makedirs(record_dir, exist_ok=True)
    os.makedirs(archive_dir, exist_ok=True)

    # 启动摄像头线程
    threads = []
    for name, url in rtsp_list.items():
        thread = CameraThread(name, url)
        thread.daemon = True
        thread.start()
        threads.append(thread)

    # 启动文件整理线程
    organizer = threading.Thread(target=organize_files, daemon=True)
    organizer.start()

    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        logging.info("\n正在停止所有录制...")
        for thread in threads:
            thread.stop()
        for thread in threads:
            thread.join()
        logging.info("所有录制已停止")